#include "pwext.hpp"
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>

struct Request
{
	bool isValid()
	{
		return false;
	}
	void handle()
	{ }
};

pw::semaphore started(0);

// [[ex05dc]]
// DEBUG descr The reliable file descriptor revocation by dup2.
class worker : public pw::pwthread
{
public:
	worker(int fd) : 
		exit_flag_(false), exit_confirm_flag_(false), 
		fd_(fd)
	{ }
	// ...
	void *execute()
	{
		while(!get_exit_flag()) {
			struct Request r;

			if (get_exit_flag())
				break;

	// DEBUG {
			fprintf(stderr, "worker thread in the loop\n");
			started.signal();
			usleep(10*1000); // artificially increase the race window
			fprintf(stderr, "worker thread is about to read the request\n");
	// DEBUG }
			int len = ::read(fd_, (char *)&r, sizeof r);
			if (len != sizeof r)
				break;

			if (get_exit_flag())
				break;
			if (!r.isValid())
				continue;

			// ... handle the request...
		}
		close(fd_);
		{
			pw::lockmutex lm(exit_mutex_);
			exit_confirm_flag_ = true;
		}
		exit_confirm_event_.signal();
	}

	void stop()
	{
		{
			pw::lockmutex lm(exit_mutex_);
			exit_flag_ = true;
		}
		exit_event_.signal();

		int nullfd;
		nullfd = open("/dev/null", O_RDONLY);
		if (nullfd < 0) { 
			// should not happen, but just in case;
			// fail-safe mode, revert to the simple close...
			if (fd_ >= 0) {
				int fd = fd_;
				fd_ = -1;
				usleep(10*1000); // 10ms = 10000 mcs
				close(fd);
			}
		} else {
			dup2(nullfd, fd_);
			close(nullfd);
		}
	}

protected:
	bool get_exit_flag()
	{
		pw::lockmutex lm(exit_mutex_);
		return exit_flag_;
	}

	bool exit_flag_;
	bool exit_confirm_flag_;
	pw::pmutex exit_mutex_;
	pw::event exit_event_;
	pw::event exit_confirm_event_;
	// ...
	int fd_; // file descriptor to read the requests from
};
// END

// DEBUG {
int main(int argc, char **argv)
{
	worker w(0);
	w.start();
	started.wait();
	w.stop();
	w.join();
}
// DEBUG }

/* Sample output:
worker thread in the loop
worker thread is about to read the request
*/
